Apple, the Apple logo, AppleScript, Bento, Macintosh, QuickTime, and OpenDoc are
registered trademarks of Apple Computer, Inc.
Finder, Mac, and QuickDraw are trademarks of Apple Computer, Inc.
SOM, SOMObjects, and System Object Model are licensed trademarks of IBM Corporation.
Changes since DR4
• The example routine MyPartFulfillPromise now demonstrates the need to reposition the storage unit view to the beginning of the focused value so the actual data overwrites the existing promise data.
Changes since DR3
• Added a recipe for forcing a promise to be fulfilled.
• Added use of the kODPropCloneKindUsed property to the recipe for fulfilling a promise.
Changes since DR2
1) Fixed refcounting method names.
2) Fixed parameter passing errors with SetValue and GetValue.
Overview
The basic mechanisms for transfering data between Parts are the Clipboard and Drag-and-Drop. If the data to be exported is very big, the part may choose to export the data as a promise. When the data is retrieved by the destination part, the source part will be requested to fulfill the promise it put out.
The format of a Promise is determined by the Part. The only restriction is that a Promise must be able to be written to a Storage Unit Value.
Recipes
Putting out a promise:
The following code fragment shows how a Part can put out a Promise in response to a mouse down event and a Drag is going to be initiated. (This recipe can also be used to put out a promise to the Clipboard).
// Prepare the promise. This section is Part specific.
MyPromise promise = .......
// Put the promise data in an ODByteArray.
ODByteArray ba;
...
// Put out the promise.
storageUnit->SetPromiseValue(
ev,
kAppleText, // type of promised data
0, // offset
&ba, // promise
fPartWrapper); // source part
// Initiate the Dragging
// Follow the drag and drop recipe.
.......
);
Getting Data From a Value with a Promise:
When the destination part retrieves the data (using ODStorageUnit::GetValue or ODStorageUnit::GetSize), the source part will be called to fulfill the promise. The destination part does not even know that the fulfilment of a promise is taking place.
The following is what the code for the destination part might look like. The same code is used whether the Value contains a promise or not.
ODDropResult YourPartDrop(YourPart* somSelf,
Environment* ev,
ODDragItemIterator* dropInfo,
ODFacet* facet,
ODPoint where)
{
ODDropResult dropResult = kODDropFail;
ODStorageUnit* dropSU;
ODBoolean notDone = kODTrue;
// iterate through the types and find a desired type
for (dropSU = dropInfo->First(ev);
dropInfo->IsNotComplete(ev) && notDone;
dropSU = dropInfo->Next(ev))
{
// If the desired type exists, import the data.
if (dropSU->Exists(ev, kODPropContents, kAppleText, 0) == kODTrue) {
// Focus to the property and value containing the desired data.
dropSU->Focus(ev,
kODPropContents,
kODPosUndefined,
kAppleText,
0,
kODPosUndefined);
// Get the size of the data.
// **** Note that the promise is being fulfilled here. But this Part
// **** does not even realize that.
ODULong size = dropSU->GetSize(ev);
// Create an ODByteArray to hold the returned data. The fields will be filled out by GetValue.
ODByteArray ba;
storageUnit->GetValue(ev, size, &ba);
// Put the data into the part’s content.
......
// Dispose the byte array buffer.
ODDisposePtr(ba._buffer);
// Stop the iteration.
notDone = kODFalse;
// Set up drop result appropriately.
dropResult = kODDropCopy;
}
}
// Return the appropriate result code.
return dropResult;
}
Fulfilling a Promise
The following code fragment is an example of what the source part might do in response to a request to fulfull a promise.
Parts must use the correct clone kind in their call to BeginClone when fulfilling a promise. All parts should check for the presense of a kODPropCloneKindUsed property in the target storage unit. If this property is present, the clone kind value there should be used; otherwise, kODCloneCopy should be used.
(Parts that don't support linking don't have to worry about writing a kODPropCloneKindUsed property. Parts that do support linking and embedding are referred to the Linking recipes for more information about the conditions when a part should write a kODPropCloneKindUsed property.)
void MyPartFulfillPromise(MyPart* somSelf,
Environment* ev,
ODStorageUnitView* promiseSUView)
{
// Do a check first to see whether it is the right size.
ODULong size = promiseSUView->GetSize(ev);
if (size == sizeof(MyPromise))
{
// Get the Promise.
// Either GetValue or GetPromiseValue can be used here.
// OpenDoc ensures that if GetValue is used, there will be no infinite recursion
// The destination will simply see a Value with no content.
// It is the responsibility of the destination part to handle invalid values.
// This is no different from the general case without promises.
}
}
Forcing Promise Fulfillment
There are times when your part might need to force the fulfillment of a promise it has written, before another part actually tries to read the data. An example of this might be when your part takes some action that would prevent it from fulfilling the promise in the future. The simplest way for a part to force a promise to be fulfilled is to focus on the promised property/value and call the storage unit routine GetSize.